// SPDX-FileCopyrightText: 2025 UnionTech Software Technology Co., Ltd.
// SPDX-License-Identifier: MIT

package config

import (
	"os"
	"testing"
)

func TestParseCommaSeparated(t *testing.T) {
	tests := []struct {
		input    string
		expected []string
	}{
		{"", []string{}},
		{"a", []string{"a"}},
		{"a,b", []string{"a", "b"}},
		{"a, b", []string{"a", "b"}},
		{" a , b ", []string{"a", "b"}},
		{"a,b,c", []string{"a", "b", "c"}},
		{"a,,b", []string{"a", "b"}},
		{",a,b,", []string{"a", "b"}},
		{"  a  ,  b  ,  c  ", []string{"a", "b", "c"}},
	}

	for _, tt := range tests {
		result := parseCommaSeparated(tt.input)
		if len(result) != len(tt.expected) {
			t.Errorf("parseCommaSeparated(%q) = %v, want %v", tt.input, result, tt.expected)
			continue
		}
		for i, v := range result {
			if v != tt.expected[i] {
				t.Errorf("parseCommaSeparated(%q)[%d] = %v, want %v", tt.input, i, v, tt.expected[i])
			}
		}
	}
}

func TestLoadFromYAML(t *testing.T) {
	// 创建临时YAML配置文件
	yamlContent := `
server:
  address: "127.0.0.1"
  port: 8080
  metrics_path: "/custom-metrics"
uwsgi:
  sockets:
    - "/tmp/test.sock"
    - "localhost:9000"
  socket_types:
    "/tmp/test.sock": "unix"
    "localhost:9000": "tcp"
logging:
  level: "debug"
  file: "/tmp/test.log"
rate_limit:
  requests_per_second: 200
`

	tmpFile, err := os.CreateTemp("", "test_config_*.yaml")
	if err != nil {
		t.Fatalf("Failed to create temp file: %v", err)
	}
	defer os.Remove(tmpFile.Name())

	if _, err := tmpFile.WriteString(yamlContent); err != nil {
		t.Fatalf("Failed to write to temp file: %v", err)
	}
	tmpFile.Close()

	// 测试配置加载
	cfg := &Config{
		Address:     "0.0.0.0",
		Port:        9070,
		MetricsPath: "/metrics",
		LogLevel:    "info",
		RateLimit:   100,
		ConfigFile:  tmpFile.Name(),
	}
	if err := cfg.loadFromFile(tmpFile.Name()); err != nil {
		t.Fatalf("Failed to load config: %v", err)
	}

	// 验证配置
	if cfg.Address != "127.0.0.1" {
		t.Errorf("Expected address '127.0.0.1', got '%s'", cfg.Address)
	}
	if cfg.Port != 8080 {
		t.Errorf("Expected port 8080, got %d", cfg.Port)
	}
	if cfg.MetricsPath != "/custom-metrics" {
		t.Errorf("Expected metrics path '/custom-metrics', got '%s'", cfg.MetricsPath)
	}
	if cfg.LogLevel != "debug" {
		t.Errorf("Expected log level 'debug', got '%s'", cfg.LogLevel)
	}
	if cfg.LogFile != "/tmp/test.log" {
		t.Errorf("Expected log file '/tmp/test.log', got '%s'", cfg.LogFile)
	}
	if cfg.RateLimit != 200 {
		t.Errorf("Expected rate limit 200, got %d", cfg.RateLimit)
	}
	if len(cfg.Sockets) != 2 {
		t.Errorf("Expected 2 sockets, got %d", len(cfg.Sockets))
	}
	if cfg.SocketTypes["/tmp/test.sock"] != "unix" {
		t.Errorf("Expected socket type 'unix' for '/tmp/test.sock', got '%s'", cfg.SocketTypes["/tmp/test.sock"])
	}
}

func TestLoadFromJSON(t *testing.T) {
	// 创建临时JSON配置文件
	jsonContent := `{
		"server": {
			"address": "0.0.0.0",
			"port": 9090,
			"metrics_path": "/metrics"
		},
		"uwsgi": {
			"sockets": ["/var/run/uwsgi.sock"],
			"socket_types": {
				"/var/run/uwsgi.sock": "unix"
			}
		},
		"logging": {
			"level": "info"
		},
		"rate_limit": {
			"requests_per_second": 150
		}
	}`

	tmpFile, err := os.CreateTemp("", "test_config_*.json")
	if err != nil {
		t.Fatalf("Failed to create temp file: %v", err)
	}
	defer os.Remove(tmpFile.Name())

	if _, err := tmpFile.WriteString(jsonContent); err != nil {
		t.Fatalf("Failed to write to temp file: %v", err)
	}
	tmpFile.Close()

	// 测试配置加载
	cfg := &Config{
		Address:     "0.0.0.0",
		Port:        9070,
		MetricsPath: "/metrics",
		LogLevel:    "info",
		RateLimit:   100,
		ConfigFile:  tmpFile.Name(),
	}
	if err := cfg.loadFromFile(tmpFile.Name()); err != nil {
		t.Fatalf("Failed to load config: %v", err)
	}

	// 验证配置
	if cfg.Address != "0.0.0.0" {
		t.Errorf("Expected address '0.0.0.0', got '%s'", cfg.Address)
	}
	if cfg.Port != 9090 {
		t.Errorf("Expected port 9090, got %d", cfg.Port)
	}
	if cfg.RateLimit != 150 {
		t.Errorf("Expected rate limit 150, got %d", cfg.RateLimit)
	}
	if len(cfg.Sockets) != 1 {
		t.Errorf("Expected 1 socket, got %d", len(cfg.Sockets))
	}
}

func TestLoadFromLegacyFormat(t *testing.T) {
	// 测试旧格式的直接配置
	yamlContent := `
address: "192.168.1.1"
port: 7070
metrics_path: "/legacy-metrics"
log_level: "warn"
log_file: "/var/log/legacy.log"
rate_limit: 300
sockets:
  - "/tmp/legacy.sock"
  - "192.168.1.100:8000"
socket_types:
  "/tmp/legacy.sock": "unix"
  "192.168.1.100:8000": "tcp"
`

	tmpFile, err := os.CreateTemp("", "test_legacy_*.yaml")
	if err != nil {
		t.Fatalf("Failed to create temp file: %v", err)
	}
	defer os.Remove(tmpFile.Name())

	if _, err := tmpFile.WriteString(yamlContent); err != nil {
		t.Fatalf("Failed to write to temp file: %v", err)
	}
	tmpFile.Close()

	// 测试配置加载
	cfg := &Config{
		Address:     "0.0.0.0",
		Port:        9070,
		MetricsPath: "/metrics",
		LogLevel:    "info",
		RateLimit:   100,
		ConfigFile:  tmpFile.Name(),
	}
	if err := cfg.loadFromFile(tmpFile.Name()); err != nil {
		t.Fatalf("Failed to load config: %v", err)
	}

	// 验证配置
	if cfg.Address != "192.168.1.1" {
		t.Errorf("Expected address '192.168.1.1', got '%s'", cfg.Address)
	}
	if cfg.Port != 7070 {
		t.Errorf("Expected port 7070, got %d", cfg.Port)
	}
	if cfg.MetricsPath != "/legacy-metrics" {
		t.Errorf("Expected metrics path '/legacy-metrics', got '%s'", cfg.MetricsPath)
	}
	if cfg.LogLevel != "warn" {
		t.Errorf("Expected log level 'warn', got '%s'", cfg.LogLevel)
	}
	if cfg.LogFile != "/var/log/legacy.log" {
		t.Errorf("Expected log file '/var/log/legacy.log', got '%s'", cfg.LogFile)
	}
	if cfg.RateLimit != 300 {
		t.Errorf("Expected rate limit 300, got %d", cfg.RateLimit)
	}
	if len(cfg.Sockets) != 2 {
		t.Errorf("Expected 2 sockets, got %d", len(cfg.Sockets))
	}
}

func TestLoadFromFileErrors(t *testing.T) {
	// 测试不存在的文件
	cfg := &Config{ConfigFile: "nonexistent.yaml"}
	if err := cfg.loadFromFile("nonexistent.yaml"); err == nil {
		t.Error("Expected error for nonexistent file, got nil")
	}

	// 测试无效的YAML格式
	tmpFile, err := os.CreateTemp("", "test_invalid_*.yaml")
	if err != nil {
		t.Fatalf("Failed to create temp file: %v", err)
	}
	defer os.Remove(tmpFile.Name())

	if _, err := tmpFile.WriteString("invalid: yaml: content"); err != nil {
		t.Fatalf("Failed to write to temp file: %v", err)
	}
	tmpFile.Close()

	if err := cfg.loadFromFile(tmpFile.Name()); err == nil {
		t.Error("Expected error for invalid YAML, got nil")
	}

	// 测试不支持的文件格式
	tmpFile2, err := os.CreateTemp("", "test_unsupported_*.txt")
	if err != nil {
		t.Fatalf("Failed to create temp file: %v", err)
	}
	defer os.Remove(tmpFile2.Name())

	if _, err := tmpFile2.WriteString("some content"); err != nil {
		t.Fatalf("Failed to write to temp file: %v", err)
	}
	tmpFile2.Close()

	if err := cfg.loadFromFile(tmpFile2.Name()); err == nil {
		t.Error("Expected error for unsupported file format, got nil")
	}
}

func TestValidate(t *testing.T) {
	tests := []struct {
		name    string
		config  *Config
		wantErr bool
	}{
		{
			name: "valid config",
			config: &Config{
				Port:      8080,
				LogLevel:  "info",
				RateLimit: 100,
				Sockets:   []string{"/tmp/test.sock"},
			},
			wantErr: false,
		},
		{
			name: "invalid port - too low",
			config: &Config{
				Port:      0,
				LogLevel:  "info",
				RateLimit: 100,
				Sockets:   []string{"/tmp/test.sock"},
			},
			wantErr: true,
		},
		{
			name: "invalid port - too high",
			config: &Config{
				Port:      70000,
				LogLevel:  "info",
				RateLimit: 100,
				Sockets:   []string{"/tmp/test.sock"},
			},
			wantErr: true,
		},
		{
			name: "no sockets",
			config: &Config{
				Port:      8080,
				LogLevel:  "info",
				RateLimit: 100,
				Sockets:   []string{},
			},
			wantErr: true,
		},
		{
			name: "invalid log level",
			config: &Config{
				Port:      8080,
				LogLevel:  "invalid",
				RateLimit: 100,
				Sockets:   []string{"/tmp/test.sock"},
			},
			wantErr: true,
		},
		{
			name: "zero rate limit (disabled)",
			config: &Config{
				Port:      8080,
				LogLevel:  "info",
				RateLimit: 0, // 0 是有效的，表示禁用限流
				Sockets:   []string{"/tmp/test.sock"},
			},
			wantErr: false,
		},
		{
			name: "negative rate limit",
			config: &Config{
				Port:      8080,
				LogLevel:  "info",
				RateLimit: -10,
				Sockets:   []string{"/tmp/test.sock"},
			},
			wantErr: true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			err := tt.config.Validate()
			if (err != nil) != tt.wantErr {
				t.Errorf("Config.Validate() error = %v, wantErr %v", err, tt.wantErr)
			}
		})
	}
}

func TestGetSocketType(t *testing.T) {
	cfg := &Config{
		SocketTypes: map[string]string{
			"/tmp/custom.sock": "unix",
			"localhost:8000":   "tcp",
		},
	}

	tests := []struct {
		socket      string
		expected    string
		description string
	}{
		{"/tmp/custom.sock", "unix", "configured unix socket"},
		{"localhost:8000", "tcp", "configured tcp socket"},
		{"/tmp/default.sock", "unix", "unix socket by path"},
		{"127.0.0.1:9000", "tcp", "tcp socket by path"},
		{"./local.sock", "unix", "relative unix socket"},
		{"./local.sock", "unix", "relative unix socket"},
		{"localhost", "tcp", "hostname without port"},
		{"192.168.1.1", "tcp", "ip address without port"},
	}

	for _, tt := range tests {
		t.Run(tt.description, func(t *testing.T) {
			result := cfg.GetSocketType(tt.socket)
			if result != tt.expected {
				t.Errorf("GetSocketType(%s) = %s, want %s", tt.socket, result, tt.expected)
			}
		})
	}
}

func TestHasSocketType(t *testing.T) {
	cfg := &Config{
		SocketTypes: map[string]string{
			"/tmp/custom.sock": "unix",
			"localhost:8000":   "tcp",
		},
	}

	tests := []struct {
		socket   string
		expected bool
	}{
		{"/tmp/custom.sock", true},
		{"localhost:8000", true},
		{"/tmp/default.sock", false},
		{"127.0.0.1:9000", false},
	}

	for _, tt := range tests {
		t.Run(tt.socket, func(t *testing.T) {
			result := cfg.HasSocketType(tt.socket)
			if result != tt.expected {
				t.Errorf("HasSocketType(%s) = %v, want %v", tt.socket, result, tt.expected)
			}
		})
	}
}

func TestGetConfigSummary(t *testing.T) {
	cfg := &Config{
		Address:     "127.0.0.1",
		Port:        8080,
		MetricsPath: "/metrics",
		LogLevel:    "info",
		RateLimit:   100,
		Sockets:     []string{"/tmp/sock1", "/tmp/sock2"},
	}

	summary := cfg.GetConfigSummary()
	expected := "Address: 127.0.0.1, Port: 8080, MetricsPath: /metrics, LogLevel: info, RateLimit: 100, Sockets: [/tmp/sock1 /tmp/sock2]"

	if summary != expected {
		t.Errorf("GetConfigSummary() = %s, want %s", summary, expected)
	}
}

func TestHasCustomArguments(t *testing.T) {
	tests := []struct {
		name     string
		config   *Config
		expected bool
	}{
		{
			name: "default config - no custom args",
			config: &Config{
				Address:     "0.0.0.0",
				Port:        9070,
				MetricsPath: "/metrics",
				LogLevel:    "info",
				RateLimit:   100,
				Sockets:     []string{},
			},
			expected: false,
		},
		{
			name: "custom address",
			config: &Config{
				Address:     "127.0.0.1",
				Port:        9070,
				MetricsPath: "/metrics",
				LogLevel:    "info",
				RateLimit:   100,
				Sockets:     []string{},
			},
			expected: true,
		},
		{
			name: "custom port",
			config: &Config{
				Address:     "0.0.0.0",
				Port:        8080,
				MetricsPath: "/metrics",
				LogLevel:    "info",
				RateLimit:   100,
				Sockets:     []string{},
			},
			expected: true,
		},
		{
			name: "custom metrics path",
			config: &Config{
				Address:     "0.0.0.0",
				Port:        9070,
				MetricsPath: "/custom-metrics",
				LogLevel:    "info",
				RateLimit:   100,
				Sockets:     []string{},
			},
			expected: true,
		},
		{
			name: "custom log level",
			config: &Config{
				Address:     "0.0.0.0",
				Port:        9070,
				MetricsPath: "/metrics",
				LogLevel:    "debug",
				RateLimit:   100,
				Sockets:     []string{},
			},
			expected: true,
		},
		{
			name: "custom rate limit",
			config: &Config{
				Address:     "0.0.0.0",
				Port:        9070,
				MetricsPath: "/metrics",
				LogLevel:    "info",
				RateLimit:   200,
				Sockets:     []string{},
			},
			expected: true,
		},
		{
			name: "custom sockets",
			config: &Config{
				Address:     "0.0.0.0",
				Port:        9070,
				MetricsPath: "/metrics",
				LogLevel:    "info",
				RateLimit:   100,
				Sockets:     []string{"/tmp/sock"},
			},
			expected: true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result := tt.config.hasCustomArguments()
			if result != tt.expected {
				t.Errorf("hasCustomArguments() = %v, want %v", result, tt.expected)
			}
		})
	}
}

func TestLoadConfiguration(t *testing.T) {
	// 测试指定配置文件的情况
	tmpFile, err := os.CreateTemp("", "test_load_config_*.yaml")
	if err != nil {
		t.Fatalf("Failed to create temp file: %v", err)
	}
	defer os.Remove(tmpFile.Name())

	yamlContent := `
server:
  address: "192.168.1.1"
  port: 7070
uwsgi:
  sockets:
    - "/tmp/test.sock"
`
	if _, err := tmpFile.WriteString(yamlContent); err != nil {
		t.Fatalf("Failed to write to temp file: %v", err)
	}
	tmpFile.Close()

	cfg := &Config{
		Address:     "0.0.0.0",
		Port:        9070,
		MetricsPath: "/metrics",
		LogLevel:    "info",
		RateLimit:   100,
		ConfigFile:  tmpFile.Name(),
	}
	if err := cfg.loadConfiguration(); err != nil {
		t.Fatalf("Failed to load configuration: %v", err)
	}

	if cfg.Address != "192.168.1.1" {
		t.Errorf("Expected address '192.168.1.1', got '%s'", cfg.Address)
	}
	if cfg.Port != 7070 {
		t.Errorf("Expected port 7070, got %d", cfg.Port)
	}
}

func TestLoadConfigurationWithCustomArgs(t *testing.T) {
	// 测试有自定义参数时不加载默认配置文件
	cfg := &Config{
		Address: "127.0.0.1", // 自定义地址
		Port:    8080,        // 自定义端口
	}

	if err := cfg.loadConfiguration(); err != nil {
		t.Fatalf("Failed to load configuration: %v", err)
	}

	// 应该保持自定义值，不加载默认配置文件
	if cfg.Address != "127.0.0.1" {
		t.Errorf("Expected address '127.0.0.1', got '%s'", cfg.Address)
	}
	if cfg.Port != 8080 {
		t.Errorf("Expected port 8080, got %d", cfg.Port)
	}
}

func TestLoadConfigurationDefaultFile(t *testing.T) {
	// 测试默认配置文件加载
	// 保存当前工作目录
	originalWd, err := os.Getwd()
	if err != nil {
		t.Fatalf("Failed to get working directory: %v", err)
	}
	defer os.Chdir(originalWd)

	// 切换到项目根目录
	if err := os.Chdir("../../"); err != nil {
		t.Fatalf("Failed to change to project root: %v", err)
	}

	originalConfig := "config/example.yaml"
	backupConfig := "config/example.yaml.backup"

	// 确保config目录存在
	if err := os.MkdirAll("config", 0755); err != nil {
		t.Fatalf("Failed to create config directory: %v", err)
	}

	if _, err := os.Stat(originalConfig); err == nil {
		// 备份原文件
		content, err := os.ReadFile(originalConfig)
		if err != nil {
			t.Fatalf("Failed to read original config: %v", err)
		}
		if err := os.WriteFile(backupConfig, content, 0644); err != nil {
			t.Fatalf("Failed to backup config: %v", err)
		}
		defer func() {
			// 恢复原文件
			if content, err := os.ReadFile(backupConfig); err == nil {
				os.WriteFile(originalConfig, content, 0644)
				os.Remove(backupConfig)
			}
		}()
	}

	// 创建测试用的默认配置文件
	testConfig := `
server:
  address: "10.0.0.1"
  port: 9999
uwsgi:
  sockets:
    - "/tmp/default.sock"
logging:
  level: "debug"
rate_limit:
  requests_per_second: 500
`
	if err := os.WriteFile(originalConfig, []byte(testConfig), 0644); err != nil {
		t.Fatalf("Failed to create test config: %v", err)
	}

	// 测试默认配置加载
	cfg := &Config{
		Address:     "0.0.0.0",
		Port:        9070,
		MetricsPath: "/metrics",
		LogLevel:    "info",
		RateLimit:   100,
		Sockets:     []string{},
	} // 无自定义参数
	if err := cfg.loadConfiguration(); err != nil {
		t.Fatalf("Failed to load default configuration: %v", err)
	}

	if cfg.Address != "10.0.0.1" {
		t.Errorf("Expected address '10.0.0.1', got '%s'", cfg.Address)
	}
	if cfg.Port != 9999 {
		t.Errorf("Expected port 9999, got %d", cfg.Port)
	}
	if cfg.LogLevel != "debug" {
		t.Errorf("Expected log level 'debug', got '%s'", cfg.LogLevel)
	}
	if cfg.RateLimit != 500 {
		t.Errorf("Expected rate limit 500, got %d", cfg.RateLimit)
	}
	if len(cfg.Sockets) != 1 || cfg.Sockets[0] != "/tmp/default.sock" {
		t.Errorf("Expected socket '/tmp/default.sock', got %v", cfg.Sockets)
	}
}

func TestLoadConfigurationDefaultFileNotExists(t *testing.T) {
	// 测试默认配置文件不存在的情况
	// 保存当前工作目录
	originalWd, err := os.Getwd()
	if err != nil {
		t.Fatalf("Failed to get working directory: %v", err)
	}
	defer os.Chdir(originalWd)

	// 切换到项目根目录
	if err := os.Chdir("../../"); err != nil {
		t.Fatalf("Failed to change to project root: %v", err)
	}

	originalConfig := "config/example.yaml"
	backupConfig := "config/example.yaml.backup"

	// 确保config目录存在
	if err := os.MkdirAll("config", 0755); err != nil {
		t.Fatalf("Failed to create config directory: %v", err)
	}

	// 备份并删除原文件
	if _, err := os.Stat(originalConfig); err == nil {
		content, err := os.ReadFile(originalConfig)
		if err != nil {
			t.Fatalf("Failed to read original config: %v", err)
		}
		if err := os.WriteFile(backupConfig, content, 0644); err != nil {
			t.Fatalf("Failed to backup config: %v", err)
		}
		defer func() {
			// 恢复原文件
			if content, err := os.ReadFile(backupConfig); err == nil {
				os.WriteFile(originalConfig, content, 0644)
				os.Remove(backupConfig)
			}
		}()
		os.Remove(originalConfig)
	}

	// 测试默认配置文件不存在时的情况
	cfg := &Config{
		Address:     "0.0.0.0",
		Port:        9070,
		MetricsPath: "/metrics",
		LogLevel:    "info",
		RateLimit:   100,
		Sockets:     []string{},
	} // 无自定义参数
	if err := cfg.loadConfiguration(); err != nil {
		t.Fatalf("Expected no error when default config doesn't exist, got: %v", err)
	}

	// 应该使用程序默认值
	if cfg.Address != "0.0.0.0" {
		t.Errorf("Expected default address '0.0.0.0', got '%s'", cfg.Address)
	}
	if cfg.Port != 9070 {
		t.Errorf("Expected default port 9070, got %d", cfg.Port)
	}
}
